package com.njtoyo.taxi.admin.service.platform.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.google.common.collect.Lists;
import com.njtoyo.taxi.admin.cache.SecondaryCachePutter;
import com.njtoyo.taxi.admin.library.Const;
import com.njtoyo.taxi.admin.library.common.util.CopyUtil;
import com.njtoyo.taxi.admin.library.jwt.JwtHelper;
import com.njtoyo.taxi.admin.library.security.PwdHelper;
import com.njtoyo.taxi.admin.mapper.master.entity.GeoCanton;
import com.njtoyo.taxi.admin.mapper.master.mapper.GeoCantonMapper;
import com.njtoyo.taxi.admin.mapper.secondary.entity.AdminUserIdentity;
import com.njtoyo.taxi.admin.mapper.secondary.entity.Role;
import com.njtoyo.taxi.admin.mapper.secondary.entity.UserRoleMapping;
import com.njtoyo.taxi.admin.mapper.secondary.enums.adminuser.AccountType;
import com.njtoyo.taxi.admin.mapper.secondary.fields.FakeMultiple;
import com.njtoyo.taxi.admin.mapper.secondary.mapper.AdminUserIdentityMapper;
import com.njtoyo.taxi.admin.mapper.secondary.mapper.AdminUserMapper;
import com.njtoyo.taxi.admin.mapper.secondary.mapper.RoleMapper;
import com.njtoyo.taxi.admin.mapper.secondary.mapper.UserRoleMappingMapper;
import com.njtoyo.taxi.admin.repository.secondary.AdminUserRepository;
import com.njtoyo.taxi.admin.repository.secondary.ResourceRepository;
import com.njtoyo.taxi.admin.rest.presenter.platfrom.AdminUserAllPresenter;
import com.njtoyo.taxi.admin.rest.presenter.platfrom.AdminUserDetailPresenter;
import com.njtoyo.taxi.admin.rest.presenter.platfrom.AdminUserIdentityPresenter;
import com.njtoyo.taxi.admin.rest.presenter.platfrom.AdminUserResourcePresenter;
import com.njtoyo.taxi.admin.rest.presenter.platfrom.adminUser.AdminUserListPresenter;
import com.njtoyo.taxi.admin.rest.presenter.platfrom.adminUser.AdminUserTokenPresenter;
import com.njtoyo.taxi.admin.rest.wrapper.platform.adminUser.*;
import com.njtoyo.taxi.admin.rest.wrapper.platform.auth.AdminUserLoginWrapper;
import com.njtoyo.taxi.admin.rest.wrapper.platform.auth.AdminUserUpdatePhoneOnlineWrapper;
import com.njtoyo.taxi.admin.service.platform.AdminUserService;
import com.njtoyo.taxi.admin.utils.encrypt.RSAEncryptionUtil;
import com.njtoyo.taxi.entity.backend.AdminUser;
import com.njtoyo.taxi.entity.backend.Enum;
import com.njtoyo.taxi.entity.backend.Resource;
import com.taxi.entity.common.RestResult;
import com.taxi.entity.common.ResultEnum;
import com.taxi.util.GeoPointUtil;
import org.dozer.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
 * @Author Dell
 * @Date 2021/6/9 16:05
 */
@Component
@DS(Const.SECONDARY_DS)
public class AdminUserServiceImpl implements AdminUserService {

    @Autowired
    private AdminUserRepository adminUserRepository;

    @Autowired
    private ResourceRepository resourceRepository;

    @Autowired
    private Mapper mapper;

    @Autowired
    private AdminUserMapper adminUserMapper;

    @Autowired
    private SecondaryCachePutter secondaryCachePutter;

    @Autowired
    private UserRoleMappingMapper userRoleMappingMapper;

    @Autowired
    private AdminUserIdentityMapper adminUserIdentityMapper;

    @Autowired
    private GeoCantonMapper geoCantonMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Value("${config.token.expireTime}")
    private Integer expireTime;

    @Value("${config.token.apiKey}")
    private String apiKey;

    /**
     * 验证对象所有信息
     *
     * @return
     */
    @Override
    public RestResult<List<AdminUserAllPresenter>> adminUserAll() {
        QueryWrapper<com.njtoyo.taxi.admin.mapper.secondary.entity.AdminUser> wrapper = new QueryWrapper<>();
        //查询的字段
        wrapper.select("id", "name", "mobile_number");
        List<com.njtoyo.taxi.admin.mapper.secondary.entity.AdminUser> list = adminUserMapper.selectList(wrapper);
        List<AdminUserAllPresenter> res =
                CopyUtil.copyList(list, AdminUserAllPresenter.class);
        return RestResult.success(res);
    }

    @Override
    public RestResult<AdminUserTokenPresenter> adminUserLogin(AdminUserLoginWrapper adminUserLoginWrapper) {
        String account = adminUserLoginWrapper.getAccount();
        adminUserLoginWrapper.setPassword(RSAEncryptionUtil.decrypt(adminUserLoginWrapper.getPassword()));
        //密码解密
        if (PhoneUtil.isPhone(account)) {
            AdminUser adminUser = adminUserRepository.findByMobileNumber(account);
            if (adminUser.getUserState() == -1) {
                return RestResult.failed("账号已被禁用");
            }
            RestResult result = validateAdminUser(adminUser, adminUserLoginWrapper);
            if (ResultEnum.NO_ADMIN_ERROR.getCode() != result.getCode()) {
                return result;
            }
        }
        AdminUser adminUser = adminUserRepository.findByAccount(account);
        return validateAdminUser(adminUser, adminUserLoginWrapper);
    }

    @Override
    public RestResult getSelfInfo(AdminUser adminUser) {
        AdminUser admin = adminUserRepository.getOne(adminUser.getId());
        AdminUserDetailPresenter presenter = new AdminUserDetailPresenter();

        mapper.map(admin, presenter);
        if (Objects.nonNull(admin.getDefaultPoint())) {
            presenter.setDefaultPoint(GeoPointUtil.getX(admin.getDefaultPoint()), GeoPointUtil.getY(admin.getDefaultPoint()));
        }
        presenter.setSuperior(adminUser.getSuperior());

        List<AdminUserIdentity> adminUserIds = adminUserIdentityMapper.selectList(new QueryWrapper<AdminUserIdentity>().eq("admin_user_id", admin.getId()));
        presenter.setIdentityIds(adminUserIds.stream().map(AdminUserIdentity::getIdentityId).collect(Collectors.toList()));

        return RestResult.success(presenter);
    }

    @Override
    public RestResult<AdminUserResourcePresenter> getResource(AdminUser adminUser) {
        AdminUserIdentityPresenter identity = (AdminUserIdentityPresenter) adminUser.getIdentity();
        AdminUserResourcePresenter resource = new AdminUserResourcePresenter();
        resource.setIdentity(identity);
        resource.setResource(adminUser.getResourceNames());
        // menu
        List<Resource> menu = resourceRepository.findByNameIn(adminUser.getResourceNames());
        resource.setMenu(menu);
        return RestResult.success(resource);
    }

    @Override
    public RestResult findAdminUserPage(AdminUserListWrapper adminUserListWrapper) {
        adminUserListWrapper.setOrders(Lists.newArrayList(new OrderItem("id", false)));
        IPage<AdminUserListPresenter> res = adminUserMapper.selectByPage(adminUserListWrapper);

        // 获取所有管理员id
        List<Long> adminUserIds = res.getRecords().stream().map(AdminUserListPresenter::getId).collect(toList());
        if (adminUserIds.size() == 0) {
            return RestResult.success(res);
        }
        // 查询角色列表
        List<Map> rolesResult = roleMapper.getRoleByUserIds(adminUserIds);
        Map<Object, List<Map>> roles = rolesResult.stream().collect(Collectors.groupingBy(o -> o.get("userId")));
        // 查询身份信息列表
        QueryWrapper<AdminUserIdentity> identityQueryWrapper = new QueryWrapper<>();
        identityQueryWrapper.in("admin_user_id", adminUserIds);
        List<AdminUserIdentity> identityResult = adminUserIdentityMapper.selectList(identityQueryWrapper);
        Map<Long, List<AdminUserIdentity>> identities = identityResult.stream().collect(Collectors.groupingBy(AdminUserIdentity::getAdminUserId));

        for (int i = 0; i < res.getRecords().size(); i++) {
            AdminUserListPresenter adminUser = res.getRecords().get(i);
            if (roles.containsKey(Integer.valueOf(adminUser.getId().toString()))) {
                List<Role> roles1 = new ArrayList<>();
                List<Map> roleList = roles.get(Integer.valueOf(adminUser.getId().toString()));
                roleList.forEach(o -> {
                    Role role = new Role();
                    role.setId((Long) o.get("id"));
                    role.setName((String) o.get("name"));
                    role.setTitle((String) o.get("title"));
                    roles1.add(role);
                });
                adminUser.setRoles(roles1);
            }
            if (identities.containsKey(adminUser.getId())) {
                adminUser.setIdentities(identities.get(adminUser.getId()));
            }
            res.getRecords().set(i, adminUser);
        }

        return RestResult.success(res);
    }

    @Override
    public RestResult logout(AdminUser adminUser) {
        secondaryCachePutter.deleteAdminUserCache((long) adminUser.getId());
        return RestResult.success();
    }

    @Override
    @Transactional
    public RestResult updateRole(Long id, AdminUserUpdateRoleWrapper updateRoleWrapper) {
        // 查询用户是否存在
        com.njtoyo.taxi.admin.mapper.secondary.entity.AdminUser adminUser = adminUserMapper.selectById(id);
        if (Objects.isNull(adminUser)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }
        // 删除用户原角色
        QueryWrapper<UserRoleMapping> wrapper = new QueryWrapper<>();
        userRoleMappingMapper.delete(wrapper.eq("user_id", id));
        // 新增用户新角色
        if (CollUtil.isNotEmpty(updateRoleWrapper.getRoleIds())) {
            ArrayList<UserRoleMapping> userRoleMappings = new ArrayList<>();
            updateRoleWrapper.getRoleIds().forEach(roleId -> {
                UserRoleMapping userRoleMapping = new UserRoleMapping();
                userRoleMapping.setUserId(id);
                userRoleMapping.setRoleId(roleId);
                userRoleMappings.add(userRoleMapping);
            });
            userRoleMappingMapper.insertBatch(userRoleMappings);
        }

        return RestResult.success();
    }

    private RestResult<AdminUserTokenPresenter> validateAdminUser(AdminUser adminUser, AdminUserLoginWrapper adminUserLoginWrapper) {
        Date now = new Date();
        if (Objects.nonNull(adminUser)) {
            Boolean result = PwdHelper.validPwd(adminUserLoginWrapper.getPassword(), adminUser.getPassword());
            if (!result) {
                return RestResult.build(ResultEnum.PWD_ERROR);
            }
            String token = JwtHelper.build(adminUser.getId().toString(), DateUtil.offsetHour(now, expireTime), apiKey);

            AdminUserTokenPresenter adminUserToken = new AdminUserTokenPresenter();
            adminUserToken.setToken(token);
            adminUserToken.setExpiresIn((long) expireTime * 3600);

            return RestResult.success(adminUserToken);
        }

        return RestResult.build(ResultEnum.NO_ADMIN_ERROR);
    }

    @Override
    @Transactional
    public RestResult updateIdentity(Long id, AdminUserUpdateIdentityWrapper updateWrapper) {
        // 查询用户是否存在
        com.njtoyo.taxi.admin.mapper.secondary.entity.AdminUser adminUser = adminUserMapper.selectById(id);
        if (Objects.isNull(adminUser)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }

        // 修改用户身份
        adminUser.setAccountType(updateWrapper.getAccountType());
        adminUserMapper.updateById(adminUser);

        // 删除用户原身份关联
        QueryWrapper<AdminUserIdentity> wrapper = new QueryWrapper<>();
        adminUserIdentityMapper.delete(wrapper.eq("admin_user_id", id));

        // 新增用户新身份关联(区域或公司类型时)
        if (!updateWrapper.getAccountType().equals(AccountType.platform) && CollUtil.isNotEmpty(updateWrapper.getIds())) {
            List<AdminUserIdentity> list = new ArrayList<>();

            updateWrapper.getIds().forEach(roleId -> {
                AdminUserIdentity adminUserIdentity = new AdminUserIdentity();

                adminUserIdentity.setAdminUserId(id);
                adminUserIdentity.setIdentityId(roleId);
                adminUserIdentity.setIdentityCategory(updateWrapper.getAccountType());

                list.add(adminUserIdentity);
            });
            adminUserIdentityMapper.insertBatch(list);
        }

        // 清理缓存
        secondaryCachePutter.deleteAdminUserCache(id);

        return RestResult.success();
    }

    @Override
    public RestResult updateFakeMultiple(Long id, FakeMultiple updateWrapper) {
        // 查询用户是否存在
        com.njtoyo.taxi.admin.mapper.secondary.entity.AdminUser adminUser = adminUserMapper.selectById(id);
        if (Objects.isNull(adminUser)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }

        // 修改用户翻倍率
        new LambdaUpdateChainWrapper<>(adminUserMapper)
                .eq(com.njtoyo.taxi.admin.mapper.secondary.entity.AdminUser::getId, id)
                .set(com.njtoyo.taxi.admin.mapper.secondary.entity.AdminUser::getFakeMultiple, this.isAllFieldNull(updateWrapper) ? null : JSON.toJSONString(updateWrapper))
                .update();

        // 清理缓存
        secondaryCachePutter.deleteAdminUserCache(id);

        return RestResult.success();
    }

    private Boolean isAllFieldNull(Object o) {
        try {
            for (Field field : o.getClass().getDeclaredFields()) {
                field.setAccessible(true);
                Object object = field.get(o);
                if (object instanceof CharSequence) {
                    if (!ObjectUtils.isEmpty(object)) {
                        return false;
                    }
                } else {
                    if (!Objects.isNull(object)) {
                        return false;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();

        }
        return true;
    }

    @Override
    public RestResult updateDefaultPoint(Long id, AdminUserUpdateDefaultPointWrapper updateWrapper) {
        // 查询用户是否存在
        com.njtoyo.taxi.admin.mapper.secondary.entity.AdminUser adminUser = adminUserMapper.selectById(id);
        if (Objects.isNull(adminUser)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }

        new LambdaUpdateChainWrapper<>(adminUserMapper)
                .eq(com.njtoyo.taxi.admin.mapper.secondary.entity.AdminUser::getId, id)
                .set(com.njtoyo.taxi.admin.mapper.secondary.entity.AdminUser::getDefaultPoint, updateWrapper.getDefaultPoint())
                .update();

        // 清理缓存
        secondaryCachePutter.deleteAdminUserCache(id);

        return RestResult.success();
    }

    @Override
    public RestResult updatePhoneOnline(AdminUser adminUser, AdminUserUpdatePhoneOnlineWrapper updateWrapper) {
        System.out.println(updateWrapper);
        new LambdaUpdateChainWrapper<>(adminUserMapper)
                .eq(com.njtoyo.taxi.admin.mapper.secondary.entity.AdminUser::getId, adminUser.getId())
                .set(com.njtoyo.taxi.admin.mapper.secondary.entity.AdminUser::getIsPhoneOnline, updateWrapper.getIsPhoneOnline())
                .update();

        // 清理缓存
        secondaryCachePutter.deleteAdminUserCache(adminUser.getId().longValue());

        return RestResult.success();
    }

    @Override
    public RestResult addHotCanton(AdminUser adminUser, HotCantonWrapper wrapper) {
        secondaryCachePutter.addHotCanton(adminUser.getId(), wrapper.getCantonId());
        return RestResult.success();
    }

    @Override
    public RestResult getHotCanton(AdminUser adminUser) {
        Set<Integer> hotCanton = secondaryCachePutter.getHotCanton(adminUser.getId());
        List<Long> hotList;
        AdminUserIdentityPresenter identity = (AdminUserIdentityPresenter) adminUser.getIdentity();
        if (Objects.isNull(hotCanton) || hotCanton.size() == 0) {
            hotList = geoCantonMapper.selectIdByIsHot();
        } else {
            hotList = hotCanton.stream().map(i -> Long.valueOf(i.toString())).collect(toList());
        }
        if (!adminUser.getAccountType().equals(Enum.AccountType.platform)) {
            List<Long> cantonIds = identity.getCantonIds();
            hotList = hotList.stream().filter(cantonIds::contains).collect(toList());
        }
        List<GeoCanton> res = new ArrayList<>();
        if (hotList.isEmpty()) {
            return RestResult.success(res);
        }
        QueryWrapper<GeoCanton> wrapper = new QueryWrapper<>();
        wrapper.in("id", hotList);
        List<GeoCanton> geoCantons = geoCantonMapper.selectList(wrapper);
        Map<Long, GeoCanton> canton = geoCantons.stream().collect(Collectors.toMap(GeoCanton::getId, i -> i));
        for (Long aLong : hotList) {
            GeoCanton item = canton.getOrDefault(aLong, null);
            if (Objects.nonNull(item)) {
                res.add(item);
            }
        }
        return RestResult.success(res);
    }

    @Override
    public RestResult create(com.njtoyo.taxi.admin.mapper.secondary.entity.AdminUser adminUser) {
        com.njtoyo.taxi.admin.mapper.secondary.entity.AdminUser account = adminUserMapper.getByAccount(adminUser.getAccount());
        if (Objects.nonNull(account)) {
            return RestResult.failed("账号已存在");
        }
        account = adminUserMapper.getByMobileNumber(adminUser.getMobileNumber());
        if (Objects.nonNull(account)) {
            return RestResult.failed("手机号已存在");
        }
        adminUser.setPassword(PwdHelper.generatePwd(adminUser.getMobileNumber().substring(5) + "@yd"))
                .setAccountType(AccountType.platform)
                .setCreatedAt(new Date())
                .setUpdatedAt(new Date());

        adminUserMapper.insert(adminUser);

        return RestResult.success();
    }

    @Override
    public RestResult updateState(Map<String, Object> param) {
        Integer id = MapUtil.getInt(param, "id");
        Integer state = MapUtil.getInt(param, "userState");
        com.njtoyo.taxi.admin.mapper.secondary.entity.AdminUser user = new  com.njtoyo.taxi.admin.mapper.secondary.entity.AdminUser();
        user.setId(id);
        user.setUserState(state);
        adminUserMapper.updateById(user);
        return RestResult.success();
    }


    public static void main(String[] args) {
        System.out.println(PwdHelper.generatePwd( "500986@yd"));
    }
}
